/*
 * RecvingFile.java
 *
 * Created on 2008年10月29日, 下午4:27
 */

package ipmsg.gui;

import ipmsg.etc.Command;
import ipmsg.etc.FileLinkList;
import ipmsg.etc.FileNode;
import ipmsg.etc.GlobalConstant;
import ipmsg.etc.GlobalVar;
import ipmsg.network.UtilityNet;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.Socket;
import javax.swing.JScrollBar;
import javax.swing.SwingUtilities;

/**
 *
 * @author  Noeru
 */
public class RecvingFile extends javax.swing.JFrame {

    /** Creates new form RecvingFile */
    private FileLinkList flist;
    private int fileSelection;
    private String savePath;
    InterfaceSetVisible_GetRecFiles inter;
    boolean replace;
    boolean cancelSafe=false;
    boolean cancelNow=false;
    
    
    private Socket socket;
    private DataInputStream inputStream;
    private DataOutputStream outputStream;
    private DataOutputStream fileOut;
    
    
    public RecvingFile(FileLinkList flist,int fileSelection,
            String savePath,InterfaceSetVisible_GetRecFiles inter,
            boolean replace) {
        this.fileSelection=fileSelection;
        this.flist=flist;
        this.savePath=savePath;
        this.replace=replace;
        this.inter=inter;
        initComponents();
        new Thread(new RecvingDeamon()).start();
        
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jPanel1 = new javax.swing.JPanel();
        jScrollPane1 = new javax.swing.JScrollPane();
        jTextArea1 = new javax.swing.JTextArea();
        jPanel2 = new javax.swing.JPanel();
        jButton1 = new javax.swing.JButton();
        jButton2 = new javax.swing.JButton();
        jLabel1 = new javax.swing.JLabel();
        jToggleButton1 = new javax.swing.JToggleButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
        setTitle("接收文件");
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                formWindowClosing(evt);
            }
        });

        jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("接收文件列表"));

        jTextArea1.setColumns(20);
        jTextArea1.setEditable(false);
        jTextArea1.setRows(5);
        jScrollPane1.setViewportView(jTextArea1);

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 352, Short.MAX_VALUE)
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 172, Short.MAX_VALUE)
        );

        getContentPane().add(jPanel1, java.awt.BorderLayout.CENTER);

        jButton1.setText("立即终止");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        jButton2.setText("安全终止");
        jButton2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton2ActionPerformed(evt);
            }
        });

        jLabel1.setText("0%");

        jToggleButton1.setText("关闭输出");
        jToggleButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jToggleButton1ActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, 89, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jToggleButton1)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jButton2)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jButton1)
                .addContainerGap())
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jButton2)
                    .addComponent(jButton1)
                    .addComponent(jLabel1)
                    .addComponent(jToggleButton1))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        getContentPane().add(jPanel2, java.awt.BorderLayout.SOUTH);

        java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        setBounds((screenSize.width-376)/2, (screenSize.height-277)/2, 376, 277);
    }// </editor-fold>//GEN-END:initComponents

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
// TODO add your handling code here:
    this.exit();
}//GEN-LAST:event_jButton1ActionPerformed

private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed
// TODO add your handling code here:
    this.cancelSafe=true;
}//GEN-LAST:event_jButton2ActionPerformed

private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
// TODO add your handling code here:
    this.exit();
}//GEN-LAST:event_formWindowClosing

private void jToggleButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jToggleButton1ActionPerformed
// TODO add your handling code here:
    if(jToggleButton1.isSelected()){
        this.jToggleButton1.setText("开启输出");
    }else{
        this.jToggleButton1.setText("关闭输出");
    }
}//GEN-LAST:event_jToggleButton1ActionPerformed


    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton jButton1;
    private javax.swing.JButton jButton2;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTextArea jTextArea1;
    private javax.swing.JToggleButton jToggleButton1;
    // End of variables declaration//GEN-END:variables

    
    private void  exit(){
        if (!UtilityGui.confirm(this, "立即终止", "正在传输中，是否继续？")) {
            return;
        }
        this.cancelNow=true;
        this.dispose();
        this.closeSocket();
        this.exitNormal();
        
    }
    
    class RecvingDeamon extends Thread{


        @Override
        public void run() {
            Command com = new Command(GlobalConstant.IPMSG_GETFILEDATA);
            try {
                if (fileSelection == flist.getFiles().size()) {
                    for (int i = 0; i < fileSelection; i++) {
                        //如果已近接受过，则无需接收。
                        if(flist.getFiles().get(i).isIsTransfered())continue;
                        initSocket();
                        //发送请求
                        com.setAdditional(Integer.toHexString(
                                flist.getPacketNo()) + ":" + 
                                Integer.toHexString(i) + ":" +
                                Integer.toHexString(0) + ":");
                        //如果是文件
                        if (flist.getFiles().get(i).getFileKind() ==
                                GlobalConstant.IPMSG_FILE_REGULAR) {
                            
                            com.resetFlag(GlobalConstant.IPMSG_GETFILEDATA);
                            outputStream.write(com.exportToBuf());
                            outputStream.flush();
                            /*this.getRegularFile(savePath +
                                    GlobalVar.FILE_PATH_DELIMITER +
                                    flist.getFiles().get(i).getFileName(),
                                    flist.getFiles().get(i).getFileLen());*/
                            this.getRegularFile(
                                this.getPath(savePath,
                                flist.getFiles().get(i).getFileName()),
                                flist.getFiles().get(i).getFileLen());
                        //如果是目录
                        } else if (flist.getFiles().get(i).getFileKind() ==
                                GlobalConstant.IPMSG_FILE_DIR){
             
                            com.resetFlag(GlobalConstant.IPMSG_GETDIRFILES);
                            outputStream.write(com.exportToBuf());
                            outputStream.flush();
                            this.getDir();
                        }
                        closeSocket();
                        if(!cancelNow)flist.getFiles().get(i).setIsTransfered(true);
                        if(cancelSafe)break;
                    }
                    //设置已经全部传输
                    //flist.transferALL();
 /////////////////////////////////////////////////////////////////////////
                } else {
                    initSocket();
                    //包编号：文件编号：偏移量
                    com.setAdditional(Integer.toHexString(
                            flist.getPacketNo()) + ":" + 
                            Integer.toHexString(fileSelection) + ":" +
                            Integer.toHexString(0) + ":");
                    //接收文件
                    if (flist.getFiles().get(fileSelection).getFileKind() ==
                            GlobalConstant.IPMSG_FILE_REGULAR) {
                        //发送请求报文
                        com.resetFlag(GlobalConstant.IPMSG_GETFILEDATA);
                        outputStream.write(com.exportToBuf());
                        outputStream.flush();
                        /*this.getRegularFile(savePath +
                                GlobalVar.FILE_PATH_DELIMITER +
                                flist.getFiles().get(fileSelection).getFileName(),
                                flist.getFiles().get(fileSelection).getFileLen());*/
                        this.getRegularFile(
                                this.getPath(savePath,
                                flist.getFiles().get(fileSelection).getFileName()),
                                flist.getFiles().get(fileSelection).getFileLen());
                        
                    //接收目录
                    } 
                    else if (flist.getFiles().get(
                            fileSelection).getFileKind() ==
                            GlobalConstant.IPMSG_FILE_DIR) {
                        //发送请求报文
                        com.resetFlag(GlobalConstant.IPMSG_GETDIRFILES);
                        outputStream.write(com.exportToBuf());
                        outputStream.flush();
                        this.getDir();
                    }
                    closeSocket();
                    if(!cancelNow)flist.getFiles().get(
                            fileSelection).setIsTransfered(true);
                }
                exitNormal();
            } catch (IOException ex) {
                System.out.println("error");
            }

        }
        
        private String getPath(String path,String filename){
            if(replace)return path+GlobalVar.FILE_PATH_DELIMITER+filename;
            else {
                while(new File(path+GlobalVar.FILE_PATH_DELIMITER+filename).exists())
                    filename=GlobalConstant.DEFAULT_FILE_PREFIX+filename;
            }
            return path+GlobalVar.FILE_PATH_DELIMITER+filename;
        }
 
        private void getRegularFile(String path, long fileLen) {
            if(!jToggleButton1.isSelected())
                appendMsg("接收文件 ： "+path);
            byte[] buf = new byte[GlobalConstant.DEFAULT_F_LENGTH];
            int read = -1,readonce=GlobalConstant.DEFAULT_F_LENGTH;
            long rest = fileLen;

            try {
                fileOut = new DataOutputStream(
                        new BufferedOutputStream(
                        new BufferedOutputStream(
                        new FileOutputStream(path))));
                
                //初始化图形显示的一些参数
                jLabel1.setText("0%");
                long percent=(fileLen/100>GlobalConstant.DEFAULT_F_LENGTH)?
                    fileLen/100:GlobalConstant.DEFAULT_F_LENGTH,
                    recvPercent=percent;
                int counter=1;
                //**

                while (true) {
                    if (inputStream != null) {
                        if(readonce>rest)readonce=(int) rest;
                        read = inputStream.read(buf,0,readonce);
                    }
                    if (read == -1) {
                        break;
                    }
                    rest -= read;
                    fileOut.write(buf, 0, read);
                    
                    //如果开启了显示
                    if(!jToggleButton1.isSelected()){
                        if(fileLen-rest>recvPercent){
                            recvPercent+=percent;
                            updatePercent up=new updatePercent();
                            up.percent=counter;
                            SwingUtilities.invokeLater(up);
                            counter++;
                        }
                    }
                    if (rest <=0) {
                        jLabel1.setText("100%");
                        break;
                    }
                }
                fileOut.flush();
                fileOut.close();
            } catch (IOException ex) {
            }

        }

        private void getDir() {
            String path = savePath;
            /*new File(path).mkdir();*/
            int depth = 0;
            FileNode fnode;
            do {
                fnode = this.getHeader();
                if(fnode==null)break;
                switch (fnode.getFileKind()) {
                    case GlobalConstant.IPMSG_FILE_REGULAR:
                        this.getRegularFile(path +
                                GlobalVar.FILE_PATH_DELIMITER +
                                fnode.getFileName(),
                                fnode.getFileLen());
                        break;
                    case GlobalConstant.IPMSG_FILE_DIR:
                        if(depth==0)path=this.getPath(path, fnode.getFileName());
                        else path = path +
                                GlobalVar.FILE_PATH_DELIMITER +
                                fnode.getFileName();
                        
                        if(!jToggleButton1.isSelected())
                            appendMsg("进入目录 ： "+path);
//                        System.out.println("进入目录 ： "+path);
                        new File(path).mkdir();
                        depth++;
                        break;
                    case GlobalConstant.IPMSG_FILE_RETPARENT:
                        if(!jToggleButton1.isSelected())
                            appendMsg("退出目录 ： "+path);
                        path = this.getParentDir(path);
                        depth--;
                        break;
                    default:
                        System.out.println("wrong file");
                }
            } while (depth > 0);

        }

        private String getParentDir(String str) {
            int len = str.lastIndexOf(GlobalVar.FILE_PATH_DELIMITER);
            if (len < 0) return null;
            return str.substring(0, len);
        }

        private FileNode getHeader() {
            int i, pos, count;
            try {
                String head = UtilityNet.readDelimiter(inputStream,100);
                if (head == null) return null;
                //需要减去header长度域的长度。
                count = Integer.parseInt(head, 16)-5;
                if(count<=0)return null;
                
                byte[] headBuf = new byte[count];
                if(inputStream.read(headBuf, 0, count)<0)return null;
                
                head = new String(headBuf,GlobalVar.CHARACTER_ENCODING);
                
                FileNode fnode = new FileNode();
                for (i = 0; i < 3;) {
                    if ((pos = head.indexOf(":")) < 0) {
                        return null;
                    }
                    count = 1;
                    while (head.charAt(++pos) == ':') {
                        count++;
                    }
                    if (count % 2 == 0) {
                        continue;
                    }
                    switch (i) {
                        case 0:
                            fnode.setFileName(head.substring(0, pos-1));
                            break;
                        case 1:
                            if (!fnode.setFileLen(head.substring(0, pos-1))) {
                                return null;
                            }
                            break;
                        case 2:
                            if (!fnode.setFileKind(head.substring(0, pos-1))) {
                                return null;
                            }
                    }
                    head = head.substring(pos);
                    i++;
                }
                return fnode;
            } catch (IOException ex) {
                return null;
            } catch (NumberFormatException e) {
                return null;
            }
        }
        
    }
    
    class updatePercent extends Thread{
        int percent;
        @Override
        public void run() {
            jLabel1.setText(this.percent+"%");
        }
        
    }
    
    private void closeSocket() {
        try {
            this.outputStream.close();
            this.inputStream.close();
            this.socket.close();
        } catch (IOException ex) {
            System.out.println("error1");
        }
    }
    
    private void initSocket() {
        try {
            //初始化变量
            socket = new Socket(flist.getIp(),
                    GlobalConstant.IPMSG_DEFAULT_PORT);
            this.outputStream = new DataOutputStream(
                    socket.getOutputStream());
            this.inputStream = new DataInputStream(
                    new BufferedInputStream(
                    socket.getInputStream()));
        } catch (Exception e) {
            System.out.println("error2");
        }
    }
    
    
    private void appendMsg(String str){
        this.jTextArea1.append(str+GlobalVar.NEW_LINE);
        JScrollBar jb = this.jScrollPane1.getVerticalScrollBar();
        jb.setValue(jb.getMaximum());
    }
        
   
    private void exitNormal(){
        this.dispose();
        this.inter.enableVisible();
    }
    
}
